﻿using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Text;
using System.Runtime.InteropServices;
using System.Media;
using Artemis;

// Just Another World War Shooter
namespace JAWWS
{
  public partial class MainForm : Form
  {
      private Timer     timer;
      private Timer     newTimer;
      private Timer animationTimer;
      float[]           sceneTheta = new float[] { 45.0f, -45.0f, 0.0f };
      double            sine = (Math.Sin(.1) * Math.Sin(.1)) / 2;
      bool              animate = false;

      //scene scale factor
      float[]           scale = new float[] { 1.0f, 1.0f, 1.0f };
      const int         SCALESTEP = 1;
      const float       MOVESTEP = 0.5f;
      const int         SCENE = 2;
      bool              startGame = false;  
     
      int                 obj;  
      uint               TexIndex;
      public uint[]      TexIDs = new uint[6];
      string[]           fileNames = new string[6];
      string[] ModelPaths = new string[2];
      string[] ModelTextures = new string[2];
   
      //camera variables
      int                startx, starty;

      // Model Stuff
      public int                NUM_MODELS = 2;

      // Sound Player
      private SoundPlayer soundPlayer = new SoundPlayer();
      public event AsyncCompletedEventHandler LoadCompleted;
      private string backMusic = @"C:\\Textures\\Kalimba.mp3";

      //to make screen full screen
      [DllImport("user32.dll")]
      private static extern int FindWindow(string className, string windowText);
      [DllImport("user32.dll")]
      private static extern int ShowWindow(int hwnd, int command);
      private const int SW_HIDE = 0;
      private const int SW_SHOW = 1; 

      //actor objects
      Actor currentActor;
      Player player;
      Enemy enemy;
      MD2Obj[] Model;
      //weapon opjects
      HandGun handgun = new HandGun();
      Rifle rifle = new Rifle();
      Knife knife = new Knife();
      NoWeapon noWeapon = new NoWeapon();
      Crosshairs crosshairs = new Crosshairs();
      Crosshairs crosshairs2 = new Crosshairs();
      Weapon currentWeapon;
      Projectile[] proj;
      private const int ALIVE_BULLETS = 10;
      int bullet = 0;
      bool fire_flag = false;

      //rooms
      int  roomidx = 0;
      Room[] rooms = new Room[4];

      //Nodes of the scene graph
      BallNode ball;
      FloorNode floor1;
      GameNode game;
      FloorNode[] floors = new FloorNode[4];
      HPItem[] hpItem = new HPItem[2];
      AmmoItem[] ammoItem = new AmmoItem[2];
      WallNode[] walls  = new WallNode[19];
      CeilingNode ceiling;
    
      // light vars      
      float[] light0_pos = { 0.0f, 2.0f - .1f, 0.0f, 1.0f };
      float[] light0_dir = { 0, -1, -1, 0.0f };
      float[] ambient = { 1.0f, 1.0f, 1.0f, .70f };
      Boolean lightFlag = true;
      LightingSetup white_light = new LightingSetup(new float[] { 0.5f, 0.5f, 0.5f, 1.0f },
               new float[] { 1.0f, 1.0f, 1.0f, 1.0f },
          new float[] { 1.0f, 1.0f, 1.0f, 1.0f });

      float[] m = new float[16];

      int ScreenHeight;
      int ScreenWidth;
      Point ScreenCenter;

    public MainForm()
    {
        Model = new MD2Obj[2];
        player = new Player(this);
        enemy = new Enemy(1, new HandGun(), this, -1.0f, 0.0f);
        proj = new Projectile[ALIVE_BULLETS];
        for (int i = 0; i < ALIVE_BULLETS; i++)
        {
            proj[i] = new Projectile(this, player);
        }
        currentActor = player;
        InitializeComponent();
        Rectangle bounds = Screen.PrimaryScreen.Bounds;

        this.Bounds = bounds;
        glSurface.Bounds = this.Bounds;
      
        // load images and models into scene
		load_images();
        loadModels();
		
        timer = new Timer();

        timer.Interval = 2000 / 60;  
        timer.Start();
        //attack timer
        newTimer = new Timer();
        newTimer.Interval = 50000 / 60;
        newTimer.Start();
        //animation timer
        animationTimer = new Timer();
        animationTimer.Interval = 6000 / 60;
        animationTimer.Start();
        
        //initialize program
        Init();
        timer.Tick += new EventHandler(timer_Tick);
        newTimer.Tick += new EventHandler(timer_Tick);
        animationTimer.Tick += new EventHandler(timer_Tick);

        ScreenHeight = glSurface.Size.Height;
        ScreenWidth = glSurface.Size.Width;
        startx = ScreenWidth / 2;
        starty = ScreenHeight / 2;
        ScreenCenter = new Point(startx, starty);
    }

    private void Init()
    {
        splashScreen();
        
        GL.glEnable(GLenum.GL_DEPTH_TEST);

        GL.glEnable(GLenum.GL_TEXTURE_2D);
        
        //textures	
        fileNames[0] = "C:\\Textures\\wood.bmp";
        fileNames[1] = "C:\\Textures\\Basketball.bmp";
        fileNames[2] = "C:\\Textures\\wall.bmp";
        fileNames[3] = "C:\\Textures\\ceiling.bmp";
        fileNames[4] = "C:\\Textures\\red_cross.jpg";
        fileNames[5] = "C:\\Textures\\poss_body.png";
        //load textures
        loadTextures();

        PlaySound("C:\\Textures\\nazi.wav");
        
        player.addToInventory(ItemName.NO_WEAPON);
        player.addToInventory(ItemName.HANDGUN);
        player.addToInventory(ItemName.RIFLE);
        player.addToInventory(ItemName.KNIFE);
        currentWeapon = player.getCurrentWeapon();

        GL.glEnable(GLenum.GL_LIGHTING);
        GL.glEnable(GLenum.GL_LIGHT0);

        //build scene graph
        create_tree();

        //game = new Map(this);
        // enabling lighting
        white_light.set_light(GLenum.GL_LIGHT0);
        GL.glLightModelfv(GLenum.GL_LIGHT_MODEL_AMBIENT, ambient);
        GL.glEnable(GLenum.GL_LIGHT0);
        GL.glLightfv(GLenum.GL_LIGHT0, GLenum.GL_POSITION, light0_pos);
        GL.glLightfv(GLenum.GL_LIGHT0, GLenum.GL_SPOT_DIRECTION, light0_dir);

        //select shading and blending methods
        GL.glShadeModel(GLenum.GL_SMOOTH);
        GL.glEnable(GLenum.GL_BLEND);
        GL.glBlendFunc(GLenum.GL_SRC_ALPHA, GLenum.GL_ONE_MINUS_SRC_ALPHA);

        // intialize shadow matrix
        for (int i = 0; i < 16; i++)
        {
            m[i] = 0.0f;
        }
        m[0] = m[5] = m[10] = 1.0f;
        m[7] = -1.0f / light0_pos[1];

        //draw text boxes.
        HealthBox.Text = "Health: " + player.getHealth().ToString();
        AmmoBox.Text = "Ammo: " + player.getCurrentWeapon().getAmmoCount().ToString();
    
    }
    
    public void create_tree()
    {
        float[] transformations = new float[11];
        float[] floorTransforms = new float[11];
        //for reading text files
        TextReader tr = new StreamReader("C:\\Textures\\setup.txt");
        TextReader map = new StreamReader("C:\\Textures\\map.txt");
        TextReader floor = new StreamReader("C:\\Textures\\floor.txt");
        
        // initalize Scene Graph nodes     
        game = new GameNode(this);
     
        ceiling = new CeilingNode(this);
        ball = new BallNode(this);
        PlayerLogic logic = new PlayerLogic();
        float[] itemPos = { 0.0f, 1.5f, 0.0f };
        hpItem[0] = new HPItem(this, itemPos);
        float[] itemPos2 = new float[3] { 0.0f, 0.5f, 3.0f };
        hpItem[1] = new HPItem(this, logic.getHPItemPosition(1));    

        float[] ammoPos = { 3.0f, 0.5f, 0.0f };
        ammoItem[0] = new AmmoItem(this, ammoPos);
        float[] ammoPos2 = {0.0f, 0.5f, -3.0f};
        ammoItem[1] = new AmmoItem(this, ammoPos2);
        // add siblings to the tree  
        //read the first line of the map file

        String lineNums = tr.ReadLine();
        tr.Close();
        // parse the string output to an int
        int numLines = int.Parse(lineNums);
        //create numLines ammoun of walls
        for(int i = 0 ; i < numLines ; i++)
        {
            walls[i] = new WallNode(this);
        }

        floors[0] = new FloorNode(this);
        floors[1] = new FloorNode(this);
        floors[2] = new FloorNode(this);
        floors[3] = new FloorNode(this);

        game.addChildNode(floors[0]);
        floors[0].addSiblingNode(floors[1]);
        floors[1].addSiblingNode(floors[2]);
        floors[2].addSiblingNode(floors[3]);

        floors[3].addSiblingNode(walls[0]); 
        for (int j = 0; j < numLines; j++)
        {
            walls[j].addSiblingNode(walls[j + 1]);
        }
        walls[numLines-1].addSiblingNode(ceiling);

        game.addSiblingNode(enemy);
        enemy.addSiblingNode(proj[0]);

        for (int i = 0; i < ALIVE_BULLETS - 1; i++)
        {
            proj[i].addSiblingNode(proj[i + 1]);
        }
        proj[ALIVE_BULLETS - 1].addSiblingNode(hpItem[0]);

        for (int h = 0; h < hpItem.Length-1 ; h++)
        {
            hpItem[h].addSiblingNode(hpItem[h + 1]);
        }
        hpItem[hpItem.Length - 1].addSiblingNode(ammoItem[0]);
        for (int k = 0; k < ammoItem.Length - 1; k++)
        {
            ammoItem[k].addSiblingNode(ammoItem[k + 1]);
        }
        GL.glEnable(GLenum.GL_BLEND);

        //read one line
        String line, line2;
        String[] lineVals = new String[numLines];
        String[] floorVal = new String[1];
        int counter = 0;
      
        float xmin = 0;
        float xmax = 0;
        float zmin = 0;
        float zmax  = 0;
        float[,] w = new float[,]{{-1.0f,-1.0f,1.0f,1.0f},
                                 {0.00f,0.00f,0.00f,0.00f},
                                 {-1.0f,1.0f,-1.0f,1.0f},
                                 {1.0f,1.0f,1.0f,1.0f}};
        int floorCounter = 0;
        // Get first wall
        if ((line = map.ReadLine()) != null )
        {
            line2 = floor.ReadLine();
            //take out all the whitespace characters in the file
            lineVals = line.Split(' ');
            floorVal = line2.Split(' ');
            //for the 8 values in the transformations array
            //load the values from the file in to the array    
            for (int j = 0; j < transformations.Length; j++)
            {
                transformations[j] = float.Parse(lineVals[j]);
                floorTransforms[j] = float.Parse(floorVal[j]);
            }
            //update node                  
            walls[counter].updateNode(transformations[0], transformations[1], transformations[2], transformations[3],
                                      transformations[4], transformations[5], transformations[6], transformations[7],
                                      transformations[8], transformations[9]);
            roomidx = (int)transformations[10];
            
            if (floorCounter < floors.Length)
            {
                floors[floorCounter].updateNode(floorTransforms[0], floorTransforms[1], floorTransforms[2], floorTransforms[3],
                                               floorTransforms[4], floorTransforms[5], floorTransforms[6], floorTransforms[7],
                                               floorTransforms[8], floorTransforms[9]);
            }
            float[] x = new float[4];
            float[] z = new float[4];
            for (int i = 0; i < 4; i++)
            {
                x[i] = w[0,i]*walls[counter].LocalTransMatrix[0] + w[1,i]*walls[counter].LocalTransMatrix[4]+w[2,i]*walls[counter].LocalTransMatrix[8]+w[3,i]*walls[counter].LocalTransMatrix[12];
                z[i] = w[0,i]*walls[counter].LocalTransMatrix[2] + w[1,i]*walls[counter].LocalTransMatrix[6]+w[2,i]*walls[counter].LocalTransMatrix[10]+w[3,i]*walls[counter].LocalTransMatrix[14];
            }
            xmin = x.Min();
            zmin = z.Min();
            xmax = x.Max();
            zmax = z.Max();
            //increment counter
            counter++;
            floorCounter++;
        }
        while ((line = map.ReadLine()) != null )
        {
            //take out all the whitespace characters in the file
            line2 = floor.ReadLine();
            lineVals = line.Split(' ');
            if (line2 != null)
            {
                floorVal = line2.Split(' ');
            }
            //for the 8 values in the transformations array
            //load the values from the file in to the array    
            for (int j = 0; j < transformations.Length; j++)
            {
                transformations[j] = float.Parse(lineVals[j]);
                floorTransforms[j] = float.Parse(floorVal[j]);
            }
            //update node                  
            walls[counter].updateNode(transformations[0], transformations[1], transformations[2], transformations[3],
                                  transformations[4], transformations[5], transformations[6], transformations[7],
                                  transformations[8], transformations[9]);
            if (floorCounter < floors.Length)
            {
            floors[floorCounter].updateNode(floorTransforms[0], floorTransforms[1], floorTransforms[2], floorTransforms[3],
                                   floorTransforms[4], floorTransforms[5], floorTransforms[6], floorTransforms[7],
                                   floorTransforms[8], floorTransforms[9]);
            }
            float[] x = new float[4];
            float[] z = new float[4];
            for (int i = 0; i < 4; i++)
            {
                x[i] = w[0, i] * walls[counter].LocalTransMatrix[0] + w[1, i] * walls[counter].LocalTransMatrix[4] + w[2, i] * walls[counter].LocalTransMatrix[8] + w[3, i] * walls[counter].LocalTransMatrix[12];
                z[i] = w[0, i] * walls[counter].LocalTransMatrix[2] + w[1, i] * walls[counter].LocalTransMatrix[6] + w[2, i] * walls[counter].LocalTransMatrix[10] + w[3, i] * walls[counter].LocalTransMatrix[14];
            }
            if ((int)transformations[10] != roomidx)
            {
                rooms[roomidx] = new Room(xmin, xmax, zmin, zmax);
                roomidx = (int)transformations[10];
                xmin = x.Min();
                zmin = z.Min();
                xmax = x.Max();
                zmax = z.Max();
            }
            if(x.Min() < xmin){
                 xmin = x.Min();
            }
            if(x.Max() > xmax){
                 xmax = x.Max();
            }
            if(z.Min() < zmin){
                  zmin = z.Min();
            }
            if( z.Max() > zmax){          
             zmax = z.Max();
            }
            //increment counter
            floorCounter++;    
            counter++;
        }
        rooms[roomidx] = new Room(xmin , xmax , zmin , zmax );

        //update any other nodes in the graph
        //floor.updateFloor();      
        ceiling.updateCeiling();
        enemy.updateEnemy();
        for (int i = 0; i < ALIVE_BULLETS; i++)
        {
            proj[i].updateProjectile();
        }
        for (int h = 0; h < hpItem.Length ; h++)
        {
            hpItem[h].updateHPItem();
        }
        for (int k = 0; k < ammoItem.Length; k++)
        {
            ammoItem[k].updateAmmoPack();
        }
        //close the open text file
        map.Close();
    }
	
    void load_images()
    {
       knife.img = Toolkit.LoadImage("C://Textures//knife_small.png", ChannelType.Auto, 0, ref knife.width, ref knife.height);
       rifle.img = Toolkit.LoadImage("C://Textures//rifle.png", ChannelType.Auto, 0, ref rifle.width, ref rifle.height);
       handgun.img = Toolkit.LoadImage("C://Textures//handgun.png", ChannelType.Auto, 0, ref handgun.width, ref handgun.height);
       crosshairs.img = Toolkit.LoadImage("C://Textures//crosshairs.png", ChannelType.Auto, 0, ref crosshairs.width, ref crosshairs.height);
       crosshairs2.img = Toolkit.LoadImage("C://Textures//crosshairs2.png", ChannelType.Auto, 0, ref crosshairs2.width, ref crosshairs2.height);
    }
   
    public void loadTextures()
    {
        for (int i = 0; i < TexIDs.Length; i++)
        {
            TexIDs[i] = Toolkit.LoadTexture(fileNames[i], 0, ChannelType.RGBA, TextureFlag.Mipmaps);
            //set application mode
            GL.glTexEnvi(GLenum.GL_TEXTURE_ENV, GLenum.GL_TEXTURE_ENV_MODE, (int)GLenum.GL_MODULATE);

            //set scaling filters
            GL.glTexParameteri(GLenum.GL_TEXTURE_2D, GLenum.GL_TEXTURE_MAG_FILTER, (int)GLenum.GL_LINEAR_MIPMAP_NEAREST);
            GL.glTexParameteri(GLenum.GL_TEXTURE_2D, GLenum.GL_TEXTURE_MIN_FILTER, (int)GLenum.GL_LINEAR_MIPMAP_NEAREST);

            //set wrapping mode

            GL.glTexParameteri(GLenum.GL_TEXTURE_2D, GLenum.GL_TEXTURE_WRAP_S, (int)GLenum.GL_REPEAT);
            GL.glTexParameteri(GLenum.GL_TEXTURE_2D, GLenum.GL_TEXTURE_WRAP_T, (int)GLenum.GL_REPEAT);
        }
    }

    void timer_Tick(Object sender, EventArgs e)
    {
        for (int i = 0; i < ALIVE_BULLETS; i++)
        {
            proj[i].moveProj();
        }
        if (sender.Equals(newTimer))
        {
            enemy.attack(player);
        }
        if (player.getHealth() <= 0)
        {
            player.setAlive(false);
            player.setHealth(0);
            DeathScreen();
        }
        if (enemy.getHealth() <= 0)
        {
            enemy.setAlive(false);
            enemy.updateEnemy();
        }
        // Checks if any HPItems are within range, if they are pick em up and use em.
        for (int i = 0; i < hpItem.Length ; i++)
        {
            float deltax = (hpItem[i].getPosition()[0] - player.getPosition()[0]);
            float deltaz = (hpItem[i].getPosition()[2] - player.getPosition()[2]);
            float len = (float)Math.Sqrt((double)(deltax * deltax + deltaz * deltaz));

            if (len < 1.0f)
            {
                if (player.getHealth() >= 100)
                {
                    if (hpItem[i].getInInventory() == false)
                    {
                        player.addItemToInventory(hpItem[i]);
                        hpItem[i].setInInventory(true);
                    }
                }
                else
                {
                  if (hpItem[i].getInInventory() == false)
                  {
                      hpItem[i].apply(player);
                      hpItem[i].setInInventory(true);
                   }
                }
            }
        }
        for (int i = 0; i < ammoItem.Length; i++)
        {
            float deltax = (ammoItem[i].getPosition()[0] - player.getPosition()[0]);
            float deltaz = (ammoItem[i].getPosition()[2] - player.getPosition()[2]);
            float len = (float)Math.Sqrt((double)(deltax * deltax + deltaz * deltaz));
            if (len < 1.0f)
            {
                if (player.getCurrentWeapon().ammoCount >= 100)
                {
                    if (ammoItem[i].getPickedUp() == false)
                    {
                        player.addItemToInventory(ammoItem[i]);
                        ammoItem[i].setPickedUp(true);
                    }
                }
                else
                {
                    if (ammoItem[i].getPickedUp() == false)
                    {
                        ammoItem[i].apply(player);
                        ammoItem[i].setPickedUp(true);
                    }
                }
            }
        }
        // advance the frames in the animations
        if (sender.Equals(animationTimer))
        {
            /// enemy move
            enemy.move(player);
            bool ok_to_move = false;
            float dx = enemy.getDx() * enemy.step;
            float dz = enemy.getDz() * enemy.step;
            for (int i = 0; i <= roomidx; i++)
            {
                if (rooms[i].check_collision(enemy.getPosition()[0], enemy.getPosition()[2]))
                {

                    ok_to_move = true;
                }
            }
            if (!ok_to_move)
            {
                enemy.setPosition(0, (float)enemy.getPosition()[0] - dx);
                enemy.setPosition(2, (float)enemy.getPosition()[2] - dz);
                enemy.movePosition(7, enemy.getSpeed());
            }
            enemy.updateEnemy();
            /// /enemy move

            // if we are at the start of an animation
            if (Model[0].getAnimation("run1").curFrame == Model[0].getAnimation("run1").startFrame)
            {
                // advance the current frame to the next frame
                Model[0].getAnimation("run1").curFrame = Model[0].getAnimation("run1").nextFrame;
                // check to make sure we arent at the the last frame with nextFrame
                if (Model[0].getAnimation("run1").nextFrame != Model[0].getAnimation("run1").endFrame)
                {
                    // if it is not at the last frame, advance the nextFrame to the frame after that
                    Model[0].getAnimation("run1").nextFrame = Model[0].getAnimation("run1").nextFrame + 1;
                }
                else
                {
                    // make nextFrame = startFrame
                    Model[0].getAnimation("run1").nextFrame = Model[0].getAnimation("run1").startFrame;
                }
            }
            // if we are in the last frame
            else if (Model[0].getAnimation("run1").curFrame == Model[0].getAnimation("run1").endFrame)
            {
                // set the curFrame to startFrame and the nextFrame to curFrame + 1
                Model[0].getAnimation("run1").curFrame = Model[0].getAnimation("run1").startFrame;
                Model[0].getAnimation("run1").nextFrame = Model[0].getAnimation("run1").curFrame + 1;
            }
            // if we are in the middle somewhere
            else if (Model[0].getAnimation("run1").curFrame != Model[0].getAnimation("run1").startFrame && Model[0].getAnimation("run1").curFrame != Model[0].getAnimation("run1").endFrame)
            {
                // set the curFrame to the nextFrame
                Model[0].getAnimation("run1").curFrame = Model[0].getAnimation("run1").nextFrame;
                // check to see if nextFrame is the endFrame
                if (Model[0].getAnimation("run1").nextFrame == Model[0].getAnimation("run1").endFrame)
                {
                    // set nextFrame to startFrame
                    Model[0].getAnimation("run1").nextFrame = Model[0].getAnimation("run1").startFrame;
                }
                // advance the nextFrame by 1
                Model[0].getAnimation("run1").nextFrame = Model[0].getAnimation("run1").curFrame + 1;
            }
        }

        HealthBox.Text = "Health: " + player.getHealth().ToString();

        glSurface.Invalidate();
    }

    private void glSurface_Resize(object sender, EventArgs e)
    {
      int w = glSurface.Width;
      int h = glSurface.Height;
      float aspectRatio = (float)w / (float)h;

      GL.glClear(GLenum.GL_COLOR_BUFFER_BIT | GLenum.GL_DEPTH_BUFFER_BIT);
      // GL & GLU functions are found as static functions in the GL & GLU classes
      GL.glViewport(0, 0, w, h);

      // Request a redraw
      glSurface.Invalidate();
    }

    private void glSurface_Paint(object sender, PaintEventArgs e)
    {
      GL.glClear(GLenum.GL_COLOR_BUFFER_BIT | GLenum.GL_DEPTH_BUFFER_BIT);
      GL.glColor3f(1.0f, 0.0f, 0.0f);
     
      GL.glMatrixMode(GLenum.GL_PROJECTION);
      GL.glLoadIdentity();
      GL.glFrustum(-0.2, 0.2, -0.2, 0.2, 0.2, 75.0);

      //Camera Work
      GL.glMatrixMode(GLenum.GL_MODELVIEW);
      GL.glLoadIdentity();

      currentActor.getCamera().setAt(currentActor.getCamera().getCam(0) + (float)Math.Cos(currentActor.getCamera().getTheta(0)) * (float)Math.Sin(currentActor.getCamera().getTheta(1)), 0);
      currentActor.getCamera().setAt(currentActor.getCamera().getCam(1) - (float)Math.Cos(currentActor.getCamera().getTheta(1)), 1);
      currentActor.getCamera().setAt(currentActor.getCamera().getCam(2) + (float)Math.Sin(currentActor.getCamera().getTheta(0))*(float)Math.Sin(currentActor.getCamera().getTheta(1)), 2);
      
      GLU.gluLookAt(currentActor.getCamera().getCam(0), currentActor.getCamera().getCam(1), currentActor.getCamera().getCam(2),
          currentActor.getCamera().getAt(0), currentActor.getCamera().getAt(1), currentActor.getCamera().getAt(2),
          currentActor.getCamera().getUp(0), currentActor.getCamera().getUp(1), currentActor.getCamera().getUp(2));

      //camera At position
      CameraText.Text = "CameraAt: " + currentActor.getCamera().getAt(0) + " " + currentActor.getCamera().getAt(1) + " " + currentActor.getCamera().getAt(2);
      CameraPos.Text = "CameraPos: " + currentActor.getCamera().getCam(0) + " " + currentActor.getCamera().getCam(1) + " " + currentActor.getCamera().getCam(2);
      // scale it based on the scale step dtermined by the +/- keys
      GL.glScalef(scale[0], scale[1], scale[2]);

      traverse(game);

      GL.glPushMatrix();
      GL.glColor3f(0.0f, 0.0f, 0.0f);
      GL.glTranslatef(0.0f, 0.5f, 0.0f);
      Toolkit.SolidCube(1.0f);
      GL.glPopMatrix();

	  // Draw weapon graphic last  
      GL.glDepthMask((byte)GLenum.GL_FALSE);

      GL.glPushMatrix();
      //GL.glLoadIdentity();
      GL.glDisable(GLenum.GL_TEXTURE);
      GL.glDisable(GLenum.GL_BLEND);
      GL.glDisable(GLenum.GL_LIGHTING);
      GL.glColor3f(1.0f, 0.0f, 0.0f);
      GL.glTranslatef(currentActor.getCamera().getAt(0), currentActor.getCamera().getAt(1), currentActor.getCamera().getAt(2));
      Toolkit.SolidSphere(0.01f, 10, 10);
      GL.glEnable(GLenum.GL_TEXTURE);
      GL.glEnable(GLenum.GL_BLEND);
      GL.glEnable(GLenum.GL_LIGHTING);
      GL.glPopMatrix();  

      //Health Shield
      if (player.getHealth() < 50)
      {
          float heal = (1.0f - (.01f * player.getHealth())) / 2.0f;

          GL.glPushMatrix();
              GL.glMatrixMode(GLenum.GL_PROJECTION);
              GL.glLoadIdentity();
              GLU.gluOrtho2D(-1.0, 1.0, -1.0, 1.0);
              GL.glMatrixMode(GLenum.GL_MODELVIEW);
              GL.glLoadIdentity();
              GL.glDisable(GLenum.GL_TEXTURE);
              GL.glDisable(GLenum.GL_LIGHTING);

              GL.glColor4f(1.0f, 0.0f, 0.0f, heal);
              GL.glBegin(GLenum.GL_POLYGON);
              GL.glVertex2f(-1.0f, -1.0f);
              GL.glVertex2f(1.0f, -1.0f);
              GL.glVertex2f(1.0f, 1.0f);
              GL.glVertex2f(-1.0f, 1.0f);
              GL.glEnd();

              GL.glEnable(GLenum.GL_TEXTURE);
              GL.glEnable(GLenum.GL_LIGHTING);
          GL.glPopMatrix();
      }
      GL.glMatrixMode(GLenum.GL_PROJECTION);
      GL.glLoadIdentity();
      GLU.gluOrtho2D(0, (double)glSurface.Width, 0.0, (double)glSurface.Height);
      GL.glMatrixMode(GLenum.GL_MODELVIEW);
      GL.glLoadIdentity();

      //weapon
      currentWeapon = player.getCurrentWeapon();
      if (currentWeapon.getWeaponType() == ItemName.HANDGUN)
      {
          GL.glRasterPos2i(glSurface.Width - handgun.width, 0);
          GL.glDrawPixels(handgun.width, handgun.height, GLenum.GL_RGBA, GLenum.GL_UNSIGNED_BYTE, handgun.img);
          GL.glRasterPos2i(glSurface.Width / 2 - crosshairs.width / 2, glSurface.Height / 2 - crosshairs.height / 2);
          GL.glDrawPixels(crosshairs.width, crosshairs.height, GLenum.GL_RGBA, GLenum.GL_UNSIGNED_BYTE, crosshairs.img);
      }
      else if (currentWeapon.getWeaponType() == ItemName.RIFLE)
      {
          GL.glRasterPos2i(glSurface.Width - rifle.width, 0);
          GL.glDrawPixels(rifle.width, rifle.height, GLenum.GL_RGBA, GLenum.GL_UNSIGNED_BYTE, rifle.img);
          GL.glRasterPos2i(glSurface.Width / 2 - crosshairs2.width / 2, glSurface.Height / 2 - crosshairs2.height / 2);
          GL.glDrawPixels(crosshairs2.width, crosshairs2.height, GLenum.GL_RGBA, GLenum.GL_UNSIGNED_BYTE, crosshairs2.img);
      }
      else if (currentWeapon.getWeaponType() == ItemName.KNIFE)
      {
          GL.glRasterPos2i(glSurface.Width - knife.width, 0);
          GL.glDrawPixels(knife.width, knife.height, GLenum.GL_RGBA, GLenum.GL_UNSIGNED_BYTE, knife.img);
      }

      GL.glDepthMask((byte)GLenum.GL_TRUE);

      GL.glFlush();
    }

    private void traverse(SceneGraphNode root)
    {
        // If null end.
        if (root == null)
        {
           return;
        }     
        //If theres still a child keep traversing.
        GL.glPushMatrix();
        GL.glMultMatrixf(root.LocalTransMatrix);
        root.draw();
         if (root.child != null)
         {
             traverse(root.child);
         }
        // If theres still a sibling keep traversing.
        GL.glPopMatrix();
         if (root.sibling != null)
         {
            traverse(root.sibling);
         }
    }
    
    private void glSurface_MouseClick(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            if (currentWeapon.getWeaponType() != ItemName.KNIFE || currentWeapon.getWeaponType() != ItemName.NO_WEAPON)
            {
                if (currentWeapon.getWeaponType() == ItemName.HANDGUN || currentWeapon.getWeaponType() == ItemName.RIFLE)
                {
                    PlaySound("C:\\Textures\\gunshot.wav");
                }
                obj = SCENE;
               
                if (currentWeapon.ammoCount > 0)
                {
                    currentWeapon.modifyAmmo(-1);

                    if (bullet == (ALIVE_BULLETS - 1))
                    {
                        bullet = 0;
                    }
                    proj[bullet].fireProj(player, currentWeapon.getWeaponType());
                    for (int i = 0; i < ALIVE_BULLETS; i++)
                    {
                        player.attack(enemy, proj[i]);
                    }
                    bullet++;
                }
                
            }
            if (currentWeapon.getWeaponType() == ItemName.KNIFE || currentWeapon.getWeaponType() == ItemName.NO_WEAPON)
            {
                AmmoBox.Text = "Ammo: " + Convert.ToChar(45) + Convert.ToChar(45);;
            }
            else
            {
                AmmoBox.Text = "Ammo: " + currentWeapon.getAmmoCount().ToString();
            }
        }
        
        startx = MousePosition.X;
        starty = MousePosition.Y;
    }

    private void glSurface_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Escape) //Exit App
        {
            if (glSurface.Visible == true) // Exit to Splash Scree
            {
                glSurface.Visible = false;
                Exit_Button.Visible = true;
                JAWWS_Menu.Visible = true;
                HealthBox.Visible = false;
                AmmoBox.Visible = false;
                pictureBox1.Visible = true;
                Cursor.Show();
            }
            else if (glSurface.Visible == false) // Back to game
            {
                glSurface.Visible = true;
                Exit_Button.Visible = false;
                JAWWS_Menu.Visible = false;
                HealthBox.Visible = true;
                AmmoBox.Visible = true;
                pictureBox1.Visible = false;
                Cursor.Hide();
            }
        }
        if (e.KeyCode == Keys.L)
        {
            lightFlag = !lightFlag;
            if (lightFlag)
            {
                GL.glEnable(GLenum.GL_LIGHT0);
            }
            else
            {
                GL.glDisable(GLenum.GL_LIGHT0);
            }
        }
        if (e.KeyCode == Keys.Add)
        {
            for (int i = 0; i < 3; i++)
            {
                scale[i] += SCALESTEP;
            }
        }
        else if (e.KeyCode == Keys.Subtract)
        {
            for (int i = 0; i < 3; i++)
            {
                scale[i] -= SCALESTEP;
            }
        }

        float dx=0.0f;
        float dz=0.0f;
        bool ok_to_move = false;
     
        // camera movement
        if (e.KeyCode == Keys.W) // Forward
        {               
            PlaySound("C:\\Textures\\footstep.wav");  
            //PlaySound("C:\\Textures\nazi.wav");
            dx = (MOVESTEP * currentActor.getSpeed()) * (float)Math.Cos(currentActor.getCamera().getTheta(0));
            dz = (MOVESTEP * currentActor.getSpeed()) * (float)Math.Sin(currentActor.getCamera().getTheta(0));

        }
        else if (e.KeyCode == Keys.S) // Backwards
        {
         
            PlaySound("C:\\Textures\\footstep.wav");
            dx = -(MOVESTEP * currentActor.getSpeed()) * (float)Math.Cos(currentActor.getCamera().getTheta(0));
            dz = -(MOVESTEP * currentActor.getSpeed()) * (float)Math.Sin(currentActor.getCamera().getTheta(0));
        }
        else if (e.KeyCode == Keys.A) // Strafe Left
        {
            PlaySound("C:\\Textures\\footstep.wav");
            dx = -(MOVESTEP * currentActor.getSpeed()) * (float)Math.Cos(currentActor.getCamera().getTheta(0));
            dz = (MOVESTEP * currentActor.getSpeed()) * (float)Math.Cos(currentActor.getCamera().getTheta(0));


               
        }
        else if (e.KeyCode == Keys.D) // Strafe Left
        {
            PlaySound("C:\\Textures\\footstep.wav");
            dx = -10 * (MOVESTEP * currentActor.getSpeed()) * (float)Math.Cos(currentActor.getCamera().getTheta(0));
            dz = (MOVESTEP * currentActor.getSpeed()) * (float)Math.Cos(currentActor.getCamera().getTheta(0));

        }
        //check collision for current room
        for (int i = 0; i <= roomidx; i++)
        {
            if (rooms[i].check_collision(currentActor.getCamera().getCam(0)+dx,currentActor.getCamera().getCam(2)+dz))                   
            {
                ok_to_move = true;
            }
        }
        if (ok_to_move)
        {
            currentActor.getCamera().setCam(currentActor.getCamera().getCam(0) + dx, 0);
            currentActor.getCamera().setCam(currentActor.getCamera().getCam(2) + dz, 2);
            currentActor.setPosition(0, (float)currentActor.getCamera().getCam(0));
            currentActor.setPosition(2, (float)currentActor.getCamera().getCam(2));
        }

        if (e.KeyCode == Keys.NumPad0)
        {
            player.switchWeapon(ItemName.NO_WEAPON);
        }
        else if (e.KeyCode == Keys.NumPad1)
        {
            player.switchWeapon(ItemName.HANDGUN);
        }
        else if (e.KeyCode == Keys.NumPad2)
        {
            player.switchWeapon(ItemName.RIFLE);
        }
        else if (e.KeyCode == Keys.NumPad3)
        {
            player.switchWeapon(ItemName.KNIFE);
        }
        currentWeapon = player.getCurrentWeapon();
       
        if (e.KeyCode == Keys.Space)
        {
            if (animate)
            {
                animate = false;
            }
            else
            {
                animate = true;
            }
        }
        if (e.KeyCode == Keys.F1)
        {
            player.useItem(ItemName.HP_ITEM);
        }
        if (e.KeyCode == Keys.F2)
        {
            player.useItem(ItemName.AMMO_PACK);
        }
        HealthBox.Text = "Health: " + player.getHealth().ToString();
        if (currentWeapon.getWeaponType() == ItemName.KNIFE || currentWeapon.getWeaponType() == ItemName.NO_WEAPON)
        {
            AmmoBox.Text = "Ammo: " + Convert.ToChar(45) + Convert.ToChar(45);
        }
        else
        {
            AmmoBox.Text = "Ammo: " + currentWeapon.getAmmoCount().ToString();
        }
        glSurface.Invalidate();
    }

    private void glSurface_KeyUp(object sender, KeyEventArgs e)
    {
    }
    
    private void MainForm_MouseMove(object sender, MouseEventArgs e)
    {
    }
    
    private void MainForm_MouseUp(object sender, MouseEventArgs e)
    {
    }
   
    private void glSurface_MouseMove(object sender, MouseEventArgs e)
    {
        int mousePosY = MousePosition.Y;
        int mousePosX = MousePosition.X;
        int mouseDeltaX = mousePosX - startx;
        int mouseDeltaY = mousePosY - starty;

        currentActor.getCamera().setTheta(currentActor.getCamera().getTheta(0) + .01f * mouseDeltaX, 0);
        currentActor.getCamera().setTheta(currentActor.getCamera().getTheta(1) + .01f * mouseDeltaY, 1);


        Theta0.Text = "Theta0: " + currentActor.getCamera().getTheta(0).ToString();
        Theta1.Text = "Theta1: " + currentActor.getCamera().getTheta(1).ToString();
       
        if (currentActor.getCamera().getTheta(1) > Math.PI)
        {
            currentActor.getCamera().setTheta((float)Math.PI, 1);
        }
        else if (currentActor.getCamera().getTheta(1) < 0)
        {
            currentActor.getCamera().setTheta(0, 1);
        }

        if (MousePosition.X == 0 || MousePosition.X >= ScreenWidth - 10)
        {
            Cursor.Position = ScreenCenter;
        }

        startx = MousePosition.X;
        starty = MousePosition.Y;
        glSurface.Invalidate();
   }

    private void glSurface_MouseEnter(object sender, EventArgs e)
    {
    }

    private void glSurface_MouseLeave(object sender, EventArgs e)
     {
     }
     
    public void loadModels()
     {
        //Model Paths
         ModelPaths[0] = "C:\\Textures\\poss_body.md2";
         ModelPaths[1] = "C:\\Textures\\poss_head.md2";

        //Texture Paths
         ModelTextures[0] = "C:\\Textures\\poss_body.pcx";
         ModelTextures[1] = "C:\\Textures\\poss_head1";

         //Loads the model Files into the game
         Model[0] = new MD2Obj();
         Model[0].setPathname(ModelPaths[0]);
         Model[0].LoadFile(Model[0].getPathname());
         Model[0].SetTexture(TexIDs[5]);
         Model[0].loadAnimation("stand1");
         Model[0].loadAnimation("run1");
         Model[0].loadAnimation("pain1");
         Model[0].loadAnimation("attack1");
         Model[0].loadAnimation("die1");
        // Set all animations
        
     }

    private void MainForm_Load(object sender, EventArgs e)
     {
         fullMaximize(sender, e);
         MediaPlayer.settings.autoStart = true;
         MediaPlayer.URL = backMusic;
     }

    private void fullMaximize(object sender, EventArgs e)
     {
         // Hide the taskbar
         int hWnd = FindWindow("Shell_TrayWnd", "");
         ShowWindow(hWnd, SW_HIDE);

         // Format and size the window.
         FormBorderStyle = FormBorderStyle.None;
         this.Location = new Point(0, 0);
         this.WindowState = FormWindowState.Maximized;
     }

    private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
     {
         // re-show Show Window
         int hwnd = FindWindow("Shell_TrayWnd", "");
         ShowWindow(hwnd, SW_SHOW);
         Cursor.Show();
     }

    private void glSurface_Load(object sender, EventArgs e)
     {
         fullMaximize(sender, e);
     }

    private void button1_Click(object sender, EventArgs e)
     {
         Application.Exit();
     }

    private void Play_Click(object sender, EventArgs e)
     {
         Cursor.Hide();
         AmmoBox.Visible = true;
         HealthBox.Visible = true;
         Play.Visible = false;
         glSurface.Visible = true;
         JAWWS_Menu.Visible = false;
         pictureBox1.Visible = false;
         glSurface.Focus();
         glSurface.Focus();
     }
    
    private void splashScreen()
     {
         Play.Visible = true;
         glSurface.Visible = false;
         JAWWS_Menu.Visible = true;
         pictureBox1.Visible = true;
     }

    public void PlaySound(string sound)
     {
         SoundPlayer music = new SoundPlayer(sound);
         try
         {
             music.SoundLocation = sound;
             music.LoadAsync();
             music.Play();
         }
         catch (Exception ex)
         {
             Console.WriteLine("Could not play file");
         }
     }
     
    public void DeathScreen()
     {
         JAWWS_Menu.Text = "You Died...";
         JAWWS_Menu.Visible = true;
         Cursor.Show();
         glSurface.Visible = false;
         AmmoBox.Visible = false;
         HealthBox.Visible = false;
         Exit_Button.Visible = true;
         pictureBox1.Visible = true;
     }

    public MD2Obj[] getModel()
     {
         return Model;
     }
  }
}
